#pragma once

using namespace System;
using namespace System::Reflection;
using namespace System::Diagnostics;

#include "m4aFile.h"


namespace m4aSharp
{
ref class TagRetriever abstract 
{
public:
	TagRetriever(void){}

	virtual Object^ RetrieveTag(m4aFile^ m4a) = 0;
};



ref class AtomTagRetriever : TagRetriever 
{
public:
	AtomTagRetriever(String^ atomPath)
	{
		Debug::Assert(String::IsNullOrEmpty(atomPath) == false);

		_atomPath = atomPath;
		_func = nullptr;
	}

	AtomTagRetriever(String^ atomPath, Func<Object^, Object^>^ func)
	{
		Debug::Assert(String::IsNullOrEmpty(atomPath) == false);

		_atomPath = atomPath;
		_func = func;
	}

	virtual Object^ RetrieveTag(m4aFile^ m4a) override
	{
		Atom^ atom = m4a->GetAtom(_atomPath);
		if (atom != nullptr)
		{
			if (_func == nullptr)
				return atom->InterpretData();

			return _func(atom->InterpretData());
		}

		return nullptr;
	}

private:
	String^ _atomPath;

	Func<Object^, Object^>^ _func;
};



ref class TrackDataTagRetriever : TagRetriever 
{
public:
	TrackDataTagRetriever(String^ propertyName)
	{
		Debug::Assert(String::IsNullOrEmpty(propertyName) == false);

		_propertyName = propertyName;
	}

	virtual Object^ RetrieveTag(m4aFile^ m4a) override
	{
		Debug::Assert(m4a != nullptr);
		Debug::Assert(m4a->Track != nullptr);

		for each (PropertyInfo^ p in m4a->Track->GetType()->GetProperties(BindingFlags::IgnoreCase | BindingFlags::Instance | BindingFlags::Public))
		{
			if (p->Name->Equals(_propertyName, StringComparison::OrdinalIgnoreCase))
				return p->GetValue(m4a->Track, nullptr);
		}

		return nullptr;
	}

private:
	String^ _propertyName;

};
}